﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using Newtonsoft.Json;
using CymaticLabs.InfluxDB.Data;
using System.Data;
using System.Reflection;
using System.Collections;
using SourceGrid;
using System.Threading;
using System.Drawing;

namespace CymaticLabs.InfluxDB.Studio.Controls
{
    /// <summary>
    /// Renders the results for a single InfluxDB query.
    /// </summary>
    public partial class QueryResultsControl : UserControl
    {
        #region Fields

        // Used to give resulting rows an ID number
        int resultsCount = 0;

        // A cache of the last results received.
        InfluxDbSeries lastResult;

        DataTable mTable = null;

        bool closing = false;
        #endregion Fields

        #region Properties

        /// <summary>
        /// Gets or sets the <see cref="InfluxDB.InfluxDbClient">InfluxDB connection</see> associated
        /// with the control.
        /// </summary>
        public InfluxDbClient InfluxDbClient { get; set; }

        /// <summary>
        /// Gets or sets the name of the database associated with the control.
        /// </summary>
        public string Database { get; set; }

        #endregion Properties

        #region Constructors

        public QueryResultsControl()
        {
            InitializeComponent();
            mTable = new DataTable("Customers");
        }

        #endregion Constructors

        #region Event Handlers

        // Export All -> CSV
        private async void exportAllCsvToolStripMenuItem_Click(object sender, EventArgs e)
        {
            await ExportToCsv();
        }

        // Export All -> JSON
        private void jSONToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ExportToJson();
        }

        // Export Selected -> CSV
        private async void exportSelectedCsvToolStripMenuItem_Click(object sender, EventArgs e)
        {
            await ExportToCsv(true);
        }

        // Export Selected -> JSON
        private void jSONToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            ExportToJson(true);
        }

        #endregion Event Handlers

        #region Methods

        /// <summary>
        /// Clears the current query results from the UI.
        /// </summary>
        public void ClearResults()
        {
            // Clear out current items
            resultsCount = 0;
            tagsTextBox.Text = null;

            mTable.BeginLoadData();
            mTable.Columns.Clear();
            mTable.Rows.Clear();
            mTable.EndLoadData();
        }

        /// <summary>
        /// Updates the query control's query results UI with the supplied result.
        /// </summary>
        /// <param name="result">The query result to render.</param>
        /// <returns>The total number of results found.</returns>
        public int UpdateResults(InfluxDbSeries result, bool clear = false)
        {
            if (result == null) throw new ArgumentNullException("result");

            // Cache
            lastResult = result;
            
            // Clear as needed
            if (clear) ClearResults();

            // Add tag values to to results
            if (result.Tags.Count > 0)
            {
                splitContainer.Panel1Collapsed = false;
                var tagCount = result.Tags.Count;
                var tagCounter = 0;
                var sb = new StringBuilder();

                foreach (var tag in result.Tags)
                {
                    sb.AppendFormat("{0} = {1}{2}", tag.Key, tag.Value, ++tagCounter < tagCount ? ", " : null);
                }

                tagsTextBox.Text = sb.ToString();
            }
            // Hide tag area if there are no tag values
            else
            {
                splitContainer.Panel1Collapsed = true;
            }

            // Start to update the list view with the new results

            // Build the first column
            mTable.Columns.Add("#", typeof(System.Int32));

            // Build the dynamic columns
            foreach (var c in result.Columns)
            {
                mTable.Columns.Add(c);
            }

            // Build the rows
            for (var i = 0; i < result.Values.Count; i++)
            {
                ArrayList tempList = new ArrayList();
                tempList.Add(++resultsCount);

                foreach (object v in result.Values[i])
                {
                    tempList.Add(v);
                }
                mTable.Rows.Add(tempList.ToArray());
                if (i >= 49)
                {
                    break;
                }
            }

            dataGrid1.SelectionMode = SourceGrid.GridSelectionMode.Row;
            dataGrid1.Selection.EnableMultiSelection = true;
            dataGrid1.DataSource = new DevAge.ComponentModel.BoundDataView(mTable.DefaultView);
            
            dataGrid1.ClipboardMode = SourceGrid.ClipboardMode.All;
            dataGrid1.Columns.AutoSizeView();
            for (int i = 0; i < dataGrid1.Columns.Count; i++)
            {
                DataGridColumn col = dataGrid1.Columns[i];
                var columnWidth = (Width - 12) / dataGrid1.Columns.Count;
                if (columnWidth < 96) columnWidth = 96;
                if (i == 0)
                {
                    col.Width = 40;
                }
                else if (col.Width < columnWidth)
                {
                    col.Width = columnWidth;
                }
            }
            
            // HACK - disable checkinf of ilegal calls
            System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;

            // ensure that thread is aborted, when we exit the form before 
            // the thread exits
            this.Disposed += delegate
            {
                closing = true;
            };
            
            // start asynchronous row addition
            if (result.Values.Count > 50)
            {
                dataGrid1.DataSource.AllowSort = false;
                new Thread(CreateData).Start();
                resultsCount = result.Values.Count;
            }
            else
            {
                dataGrid1.DataSource.AllowSort = true;
            }
            return resultsCount;
        }

        private void CreateData()
        {
            int count = 50;
            dataGrid1.SuspendLayout();
            for (int id = 50; id < lastResult.Values.Count; id++)
            {
                if (closing == true)
                    return;
                ArrayList tempList = new ArrayList();
                tempList.Add(++count);

                foreach (object v in lastResult.Values[id])
                {
                    tempList.Add(v);
                }
                mTable.Rows.Add(tempList.ToArray());

                if (id % 500 == 0)
                {
                    dataGrid1.RecalcCustomScrollBars();
                }
            }

            dataGrid1.ResumeLayout();
            dataGrid1.RecalcCustomScrollBars();
            dataGrid1.DataSource.AllowSort = true;
        }

        // Exports series data to CSV
        async Task ExportToCsv(bool onlySelected = false)
        {
            try
            {
                string l_Path = System.IO.Path.Combine(System.IO.Path.GetTempPath(), "CsvFile.csv");

                using (System.IO.StreamWriter writer = new System.IO.StreamWriter(l_Path, false, System.Text.Encoding.Default))
                {
                    SourceGrid.Exporter.CSV csv = new SourceGrid.Exporter.CSV();
                    csv.Export(dataGrid1, writer);
                    writer.Close();
                }

                DevAge.Shell.Utilities.OpenFile(l_Path);
            }
            catch (Exception err)
            {
                DevAge.Windows.Forms.ErrorDialog.Show(this, err, "CSV Export Error");
            }
        }

        // Exports series data to a JSON array
        void ExportToJson(bool onlySelected = false)
        {
            
        }

        #endregion Methods

        private void splitContainer_Paint(object sender, PaintEventArgs e)
        {
            Graphics graphics = splitContainer.CreateGraphics();

            graphics.DrawRectangle(new Pen(Color.Green), new Rectangle(1, 1, splitContainer.Width - 2, splitContainer.Height - 2));
        }

        private async void exportCSVToolStripMenuItem_Click(object sender, EventArgs e)
        {
            await ExportToCsv();
        }
    }
}
